/*
 * Created on 03.apr.2006
 * Created by Tomas
 */
package people;

import placing.Place;
import placing.PlaceNotFoundException;
import util.Debug;


/**
 * 
 * <p>A Person that can be assigned to a place. The Person contains information
 * about the real person it represents, and allows for scoring of the Person.</p>
 * 
 * @author Tomas Ekeli
 *
 */
public class Person implements Comparable<Person>, Reserver{
	private Name name;
	private String  mail, comment;
	private int id;
	private boolean isAssigned;
	private Place prefPlace;
	private Place assignedPlace;
	private int score;
	
	
	/**
	 * Creates a new Person with only the minimal information.
	 * @param num The identifying number of the Person
	 * @param fn The first name of the Person
	 * @param ln The last name of the Person
	 */
	public Person(int num, String fn, String ln) {
		name = new Name(fn, ln);
		id = num;
		assignedPlace = null;
		comment = "";
	}
	
	/**
	 * Creates a new Person as defined by the parameters (doh!).
	 * @param num The identifying number of the Person
	 * @param fn The first name of the Person
	 * @param ln The last name of the Person
	 * @param comm A comment about the Person. Be nice.
	 * @param preference The preferred place of the Person.
	 */
	public Person(int num, String fn, String ln, String email, String comm, Place preference) {
		name = new Name(fn, ln);
		id = num;
		mail = email;
		comment = comm;
		prefPlace = preference;
		isAssigned = false;
		score = 0;
		assignedPlace = null;
	}

	public Person(int num, String fn, String ln, String email, String comm) {
		name = new Name(fn, ln);
		id = num;
		mail = email;
		comment = comm;
		isAssigned = false;
		score = 0;
		assignedPlace = null;
	}

	/**
	 * Fetches the score of the Person.
	 * 
	 * @return The current score of the Person.
	 */
	public int getScore() {
		return score;
	}

	/**
	 * Returns the Person's name.
	 * 
	 * @return The name of this Person.
	 */
	public String getName() {
		return name.toString();
	}
	
	public Name getNameObject() {
		return name;
	}

	/**
	 * Returns the Place assigned to the Person. If the Person doesn't have
	 * a Place assigned to it, <code>null</code> is returned.
	 * @return The Place the Person is at, <code>null</code> if no place.
	 */
	public Place getPlace() {
		return assignedPlace;
	}

	/**
	 * <code>true</code> iff the other object is a Person with the same
	 * name and number
	 * 
	 * @return <code>true</code> iff this and <code>other</code> are the same.
	 */
	public boolean equals(Object other) {
		Person s = (Person)other;
		return (id == s.getID() && name.toString().equals(s.getName()));
	}

	/**
	 * <p>Compares to another Person, based on the Score.</p>
	 *  
	 * <p>This comparator returns non-obvious results. 200 compared to 250 
	 * would return 50, not -50 as one would expect. This is because the Queue 
	 * should put highest scores first.</p>
	 * 
	 * <p>Further, two persons with equal scores will receive a difference iff 
	 * they don't have the same identifier. </p>
	 * 
	 * <p>The effect of this is that Persons will be sorted descending in score
	 * with equal scores being sorted based on the identifying number.</p>
	 * 
	 */
	public int compareTo(Person o) {
		if (equals(o)) {
			return 0;
		}
		
		int result = o.getScore() - score;
		
		if (result == 0) {
			result = id - o.getID();
		}
//		if (Debug.ON) {
//			System.out.println("Comparing " + sName + " to " + o.getName() + ": " + result);
//		}
		return result;
	}

	@Override
	public String toString() {
		
		if (Debug.ON) {
			return score + " " + name + ", " + mail + ", " + id;
		}
		
		return name.toString();
	}
		
	/**
	 * Sets this Person's status to assigned, and stores the Place it's assigned
	 * to.
	 *
	 */
	public void assign(Place p) {
		assignedPlace = p;
		isAssigned = true;
	}
	
	/**
	 * Sets this Person's status to unassigned.
	 *
	 */
	public void unAssign() {
		assignedPlace = null;
		isAssigned = false;
	}
	
	/**
	 * Checks whether the Person has been assigned.
	 * 
	 * @return true iff this Person's status is assigned.
	 */
	public boolean isAssigned() {
		return isAssigned;
	}
	
	/**
	 * Returns the Place that this Person is currently assigned to, if any.
	 * 
	 * @return The Place this Person "owns"
	 * @throws PlaceNotFoundException iff the Person is not assigned to a Place
	 */
	public Place getCurrentPlace() throws PlaceNotFoundException {
		if (isAssigned) {
			return assignedPlace;
		}
		throw new PlaceNotFoundException(id + " not assigned to a place.");
	}
	
	
	/**
	 * Returns the uniquely identifying number of the Person. No two Persons can
	 * have the same number. If two separate Persons have the same number the
	 * behaviour of the system is unknown and everything will probably break. 
	 * Or perhaps one of them will just be deleted.
	 * 
	 * @return The identifying number of this Person.
	 */
	public int getID() {
		return id;
	}

	/**
	 * Sets the preferred Place of the Person.
	 * 
	 * @param pref The preferential place of this Person, if any.
	 */
	public void addPreferredPlace(Place pref) {
		prefPlace = pref;
		pref.setPreferredBy(this);
	}
	
	/**
	 * Fetches the preferred Place of the Person.
	 * 
	 * @return The preferential place of this Person, if none <code>null</code>
	 * is returned.
	 */
	public Place getPreferredPlace() {
		return prefPlace;
	}

	/**
	 * Tests for the existence of a preferred Place.
	 * 
	 * @return <code>true</code> iff this Person has a preferred Place.
	 */
	public boolean hasPreferredPlace() {
		return prefPlace != null;
	}
	
	/**
	 * Remove any preferred Place that the Person might have had.
	 *
	 */
	protected void removePreferrence() {
		prefPlace = null;
	}

	/**
	 * Fetches the comment associated with the Person.
	 * 
	 * @return The comment associated with this Person, may be <code>null</code>
	 */
	public String getComment() {
		
		return comment;
	}

	/**
	 * Associates a comment to the Person. This will overwrite any previous 
	 * comment.
	 * 
	 * @param comm The comment to associate with this Person
	 */
	public void setComment(String comm) {
		comment = comm;
	}
	
	/**
	 * Tests whether there is a comment associated with the Person.
	 * 
	 * @return <code>true</code> iff there is a commen associated with this 
	 * Person
	 */
	protected boolean hasComment() {
		return comment != null;
	}

	
	/**
	 * Fetches the email of the Person
	 * 
	 * @return The address of the Person
	 */
	public String getEmail() {
		return mail;
	}

	/**
	 * Sets the email of the Person. This will overwrite any previous value.
	 * 
	 * @param email The e-mail adress of this Person
	 */
	protected void setEmail(String email) {
		mail = email;
	}

	/**
	 * Increases the score of the Person by the value given.
	 * 
	 * @param val The amount to increase score by.
	 */
	protected void addToScore(int val) {
		score += val;
	}
	
	/**
	 * Sets the score of the Person to the value given. This will overwrite the
	 * score stored so far, ie. <code>setScore(0)</code> resets the score.
	 * 
	 * @param val The new score of the Person.
	 */
	public void setScore(int val) {
		score = val;
	}
	
	
}
